home *** CD-ROM | disk | FTP | other *** search
/ Mac Power 1997 January / macpower199701.bin / AMUG / Programming_10 / WASTE 1.3a1.sit / WASTE 1.3a1 Distribution / WASTE 1.3a1 / WEHighLevelEditing.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-08-23  |  33.7 KB  |  1,446 lines  |  [TEXT/CWIE]

  1. /*
  2.  *    WEHighLevelEditing.c
  3.  *
  4.  *    WASTE PROJECT
  5.  *  High-Level Editing Routines
  6.  *
  7.  *  Copyright (c) 1993-1996 Marco Piovanelli
  8.  *    All Rights Reserved
  9.  *
  10.  *  C port by Dan Crevier
  11.  *
  12.  */
  13.  
  14.  
  15. #include "WASTEIntf.h"
  16.  
  17. pascal void _WEPushAction(WEActionHandle hAction)
  18. {
  19.     WEPtr pWE = *((*hAction)->hOwner);
  20.     WEActionHandle hLast;
  21.  
  22.     // find the last action in the given stack
  23.     for ( hLast = hAction; (*hLast)->hNext != nil; hLast = (*hLast)->hNext )
  24.         ;
  25.  
  26.     // prepend hAction in front of the action stack
  27.     (*hLast)->hNext = pWE->hActionStack;
  28.     pWE->hActionStack = hAction;
  29. }
  30.  
  31. pascal OSErr _WENewAction(SInt32 rangeStart, SInt32 rangeEnd, SInt32 newTextLength,
  32.                             WEActionKind actionKind, WEActionFlags actionFlags,
  33.                             WEHandle hWE, WEActionHandle *hAction)
  34. {
  35.     WEActionPtr pAction;
  36.     OSErr err;
  37.  
  38.     // allocate a new action record
  39.     if ((err = _WEAllocate(sizeof(WEAction), kAllocClear, (Handle *)hAction)) != noErr)
  40.         goto cleanup1;
  41.  
  42.     // lock it down
  43.     HLock((Handle) *hAction);
  44.     pAction = **hAction;
  45.  
  46.     // fill in the fields
  47.     pAction->hOwner = hWE;
  48.     pAction->delRangeStart = rangeStart;
  49.     pAction->delRangeLength = newTextLength;
  50.     pAction->insRangeLength = rangeEnd - rangeStart;
  51.     pAction->actionKind = actionKind;
  52.     pAction->actionFlags = actionFlags;
  53.  
  54.     // remember selection range
  55.     WEGetSelection(&pAction->hiliteStart, &pAction->hiliteEnd, hWE);
  56.  
  57.     // allocate a handle to hold the text to be saved, unless otherwise specified
  58.     if ((actionFlags & weAFDontSaveText) == 0)
  59.     {
  60.         if ((err = _WEAllocate(0, kAllocTemp, &pAction->hText)) != noErr)
  61.             goto cleanup1;
  62.     }
  63.  
  64.     // allocate a handle to hold the styles to be saved, unless otherwise specified
  65.     if ((actionFlags & weAFDontSaveStyles) == 0)
  66.     {
  67.         if ((err = _WEAllocate(0, kAllocTemp, &pAction->hStyles)) != noErr)
  68.             goto cleanup1;
  69.     }
  70.  
  71. #if WASTE_OBJECTS
  72.     // allocate a handle to hold the "soup" to be saved, unless otherwise specified
  73.     if ((actionFlags & weAFDontSaveSoup) == 0)
  74.     {
  75.         if ((err = _WEAllocate(0, kAllocTemp, &pAction->hSoup)) != noErr)
  76.             goto cleanup1;
  77.     }
  78. #endif
  79.  
  80.     // make a copy of text range
  81.     if ((err = WECopyRange(rangeStart, rangeEnd, pAction->hText,
  82.             (Handle) pAction->hStyles, pAction->hSoup, hWE)) != noErr)
  83.         goto cleanup1;
  84.  
  85.     // unlock action record
  86.     HUnlock((Handle) *hAction);
  87.  
  88.     // skip clean-up section
  89.     goto cleanup0;
  90.  
  91. cleanup1:
  92.     // clean up
  93.     _WEForgetHandle(&pAction->hText);
  94.     _WEForgetHandle(&pAction->hStyles);
  95. #if WASTE_OBJECTS
  96.     _WEForgetHandle(&pAction->hSoup);
  97. #endif
  98.     _WEForgetHandle((Handle *)hAction);
  99.  
  100. cleanup0:
  101.     // return result code
  102.     return err;
  103.  
  104. }
  105.  
  106. pascal void _WEDisposeAction(WEActionHandle hAction)
  107. {
  108.     WEActionPtr pAction;
  109.     WEActionHandle hNext;
  110.  
  111.     for ( ; hAction != nil; hAction = hNext )
  112.     {
  113.         // lock the action record
  114.         HLock((Handle) hAction);
  115.         pAction = *hAction;
  116.         hNext = pAction->hNext;
  117.  
  118.         // throw away text, styles and soup
  119.         _WEForgetHandle(&pAction->hText);
  120.         _WEForgetHandle(&pAction->hStyles);
  121. #if WASTE_OBJECTS
  122.         _WEForgetHandle(&pAction->hSoup);
  123. #endif
  124.  
  125.         // throw away the action record itself
  126.         DisposeHandle((Handle) hAction);
  127.     }
  128. }
  129.  
  130. pascal void _WEForgetAction(WEActionHandle *hAction)
  131. {
  132.     WEActionHandle theAction;
  133.  
  134.     theAction = *hAction;
  135.     if (theAction != nil)
  136.     {
  137.         *hAction = nil;
  138.         _WEDisposeAction(theAction);
  139.     }
  140. }
  141.  
  142. pascal OSErr _WEDoAction(WEActionHandle hAction)
  143. {
  144.     WEActionHandle hRedoAction;
  145.     WEActionPtr pAction;
  146.     WEHandle hWE;
  147.     WEPtr pWE;
  148.     SInt32 offset, delOffset, insOffset;
  149.     SInt32 redrawStart, redrawEnd;
  150.     Boolean saveActionLock, saveWELock, saveTextLock;
  151.     OSErr err;
  152.  
  153.     // sanity check: make sure hAction isn't nil
  154.     if (hAction == nil)
  155.     {
  156.         return nilHandleErr;
  157.     }
  158.  
  159.     // get handle to associated WE instance
  160.     hWE = (*hAction)->hOwner;
  161.  
  162.     // lock the WE record
  163.     saveWELock = _WESetHandleLock((Handle) hWE, true);
  164.     pWE = *hWE;
  165.  
  166.     // return an error code if this instance is read-only
  167.     err = weReadOnlyErr;
  168.     if (BTST(pWE->features, weFReadOnly))
  169.         goto cleanup;
  170.  
  171.     // stop any ongoing inline input session
  172.     WEStopInlineSession(hWE);
  173.  
  174.     // hide selection highlighting and the caret
  175.     _WEHiliteRange(pWE->selStart, pWE->selEnd, hWE);
  176.     if (BTST(pWE->flags, weFCaretVisible))
  177.         _WEBlinkCaret(hWE);
  178.  
  179.     redrawStart = LONG_MAX;
  180.     redrawEnd = 0;
  181.  
  182.     for ( ; hAction != nil; hAction = (*hAction)->hNext )
  183.     {
  184.         // lock the action record
  185.         saveActionLock = _WESetHandleLock((Handle) hAction, true);
  186.         pAction = *hAction;
  187.         offset = pAction->delRangeStart;
  188.         delOffset = offset + pAction->delRangeLength;
  189.         insOffset = offset + pAction->insRangeLength;
  190.  
  191.         // update the modification count of the affected WE instance
  192.         // note that undoing a change _decrements_ the modification count,
  193.         // while redoing the change increments it again
  194.         if (pAction->actionFlags & weAFIsRedo)
  195.         {
  196.             pWE->modCount++;
  197.         }
  198.         else
  199.         {
  200.             pWE->modCount--;
  201.         }
  202.  
  203.         // if undo support is enabled, save the range to be affected by this action
  204.         if (BTST(pWE->features, weFUndoSupport))
  205.         {
  206.             if (_WENewAction(offset, delOffset, pAction->insRangeLength, pAction->actionKind,
  207.                 (pAction->actionFlags ^ weAFIsRedo), hWE, &hRedoAction) == noErr)
  208.             {
  209.                 _WEPushAction(hRedoAction);
  210.             }
  211.         }
  212.  
  213.         if (pAction->hText != nil)
  214.         {
  215.             // delete the range to replace
  216.             if ((err = _WEDeleteRange(offset, delOffset, hWE)) != noErr)
  217.             {
  218.                 goto cleanup;
  219.             }
  220.  
  221.             // insert the saved text
  222.             saveTextLock = _WESetHandleLock(pAction->hText, true);
  223.             err = _WEInsertText(offset, *pAction->hText, pAction->insRangeLength, hWE);
  224.             _WESetHandleLock(pAction->hText, saveTextLock);
  225.             if (err != noErr)
  226.             {
  227.                 goto cleanup;
  228.             }
  229.         }
  230.  
  231.         // apply the saved styles, if any
  232.         if (pAction->hStyles != nil)
  233.         {
  234.             if ((err = _WEApplyStyleScrap(offset, insOffset, (StScrpHandle) pAction->hStyles, hWE)) != noErr)
  235.             {
  236.                 goto cleanup;
  237.             }
  238.         }
  239.  
  240. #if WASTE_OBJECTS
  241.         // the same goes for the soup
  242.         if (pAction->hSoup != nil)
  243.         {
  244.             if ((err = _WEApplySoup(offset, pAction->hSoup, hWE)) != noErr)
  245.             {
  246.                 goto cleanup;
  247.             }
  248.         }
  249. #endif
  250.  
  251.         // adjust redraw range (??? will this work with "complex" action stacks ???)
  252.         if (offset < redrawStart)
  253.         {
  254.             redrawStart = offset;
  255.         }
  256.         if (insOffset > redrawEnd)
  257.         {
  258.             redrawEnd = insOffset;
  259.         }
  260.  
  261.         // unlock action record
  262.         _WESetHandleLock((Handle) hAction, saveActionLock);
  263.  
  264.     } // for
  265.  
  266.     // restore the original selection range
  267.     pWE->selStart = pAction->hiliteStart;
  268.     pWE->selEnd = pAction->hiliteEnd;
  269.  
  270.     // redraw the text
  271.     if ((err = _WERedraw(redrawStart, redrawEnd, hWE)) != noErr)
  272.     {
  273.         goto cleanup;
  274.     }
  275.  
  276.     // clear result code
  277.     err = noErr;
  278.  
  279. cleanup:
  280.     // unlock the WE record
  281.     _WESetHandleLock((Handle) hWE, saveWELock);
  282.  
  283.     // return result code
  284.     return err;
  285. }
  286.  
  287. pascal OSErr WEUndo(WEHandle hWE)
  288. {
  289.     WEPtr pWE;
  290.     WEActionHandle hAction;
  291.     Boolean saveWELock;
  292.     OSErr err;
  293.  
  294.     // lock the WE record
  295.     saveWELock = _WESetHandleLock((Handle) hWE, true);
  296.     pWE = *hWE;
  297.  
  298.     // "detach" the action stack from the WE instance
  299.     hAction = pWE->hActionStack;
  300.     pWE->hActionStack = nil;
  301.  
  302.     if (hAction != nil)
  303.     {
  304.         // perform the action...
  305.         err = _WEDoAction(hAction);
  306.  
  307.         // ...and throw it away
  308.         _WEDisposeAction(hAction);
  309.     }
  310.     else
  311.     {
  312.         // return an error code if the undo buffer is empty
  313.         err = weCantUndoErr;
  314.     }
  315.  
  316.     // unlock the WE record
  317.     _WESetHandleLock((Handle) hWE, saveWELock);
  318.  
  319.     return err;
  320. }
  321.  
  322. pascal void WEClearUndo(WEHandle hWE)
  323. {
  324.     WEPtr pWE = *hWE;
  325.  
  326.     // dispose of the action chain associated with the given WE instance,
  327.     // unless weFAccumulateUndos is set
  328.     if (! BTST(pWE->flags, weFAccumulateUndos))
  329.     {
  330.         _WEForgetAction(&pWE->hActionStack);
  331.     }
  332. }
  333.  
  334. pascal WEActionKind WEGetUndoInfo(Boolean *redoFlag, WEHandle hWE)
  335. {
  336.     WEActionHandle hAction;
  337.     WEActionKind theKind = weAKNone;
  338.     Boolean theFlag = false;
  339.  
  340.     if ((hAction = (*hWE)->hActionStack) != nil)
  341.     {
  342.         theKind = (*hAction)->actionKind;
  343.         theFlag = (((*hAction)->actionFlags & weAFIsRedo) != 0);
  344.     }
  345.  
  346.     if (redoFlag != nil)
  347.     {
  348.         *redoFlag = theFlag;
  349.     }
  350.     return theKind;
  351. }
  352.  
  353. pascal OSErr WEBeginAction(WEHandle hWE)
  354. {
  355.     WEPtr pWE = *hWE;
  356.  
  357.     if (BTST(pWE->flags, weFAccumulateUndos))
  358.     {
  359.         //    calling WEBeginAction twice in a row
  360.         //    is considered a protocol error
  361.         return weProtocolErr;
  362.     }
  363.  
  364.     //    set weFAccumulateUndos so that each new change will add to,
  365.     //    rather than replace, the existing action stack
  366.     BSET(pWE->flags, weFAccumulateUndos);
  367.  
  368.     //    start with a fresh action stack
  369.     _WEForgetAction(&pWE->hActionStack);
  370.  
  371.     return noErr;
  372. }
  373.  
  374. pascal OSErr WEEndAction(WEActionKind actionKind, WEHandle hWE)
  375. {
  376.     WEPtr pWE = *hWE;
  377.  
  378.     if (! BTST(pWE->flags, weFAccumulateUndos))
  379.     {
  380.         //    a call to WEEndAction not balanced by a previous
  381.         //    call to WEBeginAction is a protocol error
  382.         return weProtocolErr;
  383.     }
  384.  
  385.     //    stop accumulating actions
  386.     BCLR(pWE->flags, weFAccumulateUndos);
  387.  
  388.     //    make sure we have a non-empty action stack
  389.     if (pWE->hActionStack == nil)
  390.     {
  391.         return weCantUndoErr;
  392.     }
  393.  
  394.     //    set the action kind
  395.     (*pWE->hActionStack)->actionKind = actionKind;
  396.  
  397.     return noErr;
  398. }
  399.  
  400. pascal UInt32 WEGetModCount(WEHandle hWE)
  401. {
  402.     return (*hWE)->modCount;
  403. }
  404.  
  405. pascal void WEResetModCount(WEHandle hWE)
  406. {
  407.     (*hWE)->modCount = 0;
  408.     _WEForgetAction(&(*hWE)->hActionStack);
  409. }
  410.  
  411. pascal void _WEAdjustUndoRange(SInt32 moreBytes, WEHandle hWE)
  412. {
  413.     WEActionHandle hAction;
  414.  
  415.     if ((hAction = (*hWE)->hActionStack) != nil)
  416.     {
  417.         (*hAction)->delRangeLength += moreBytes;
  418.     }
  419. }
  420.  
  421. pascal OSErr _WETypeChar(char theByte, WEHandle hWE)
  422. {
  423.     WEPtr pWE;
  424.     char db[2];
  425.     SInt32 offset, endOffset, charLength;
  426.     OSErr err;
  427.  
  428.     pWE = *hWE;                    // the WE record must be already locked
  429.     charLength = 1;                // assume 1-byte character by default
  430.     db[0] = theByte;
  431.     offset = pWE->selStart;
  432.  
  433.     // delete current selection, if any
  434.     if ((err = _WEDeleteRange(offset, pWE->selEnd, hWE)) != noErr)
  435.         goto cleanup2;
  436.  
  437.     pWE->selEnd = offset; // needed in case we take a premature exit
  438.  
  439.     // make sure the font script is synchronized with the keyboard script
  440.     _WESynchNullStyle(hWE);
  441.  
  442.     if (BTST(pWE->flags, weFDoubleByte))
  443.     {
  444.  
  445.         // special processing for double-byte characters
  446.         if (pWE->firstByte != 0)
  447.         {
  448.  
  449.             // if this byte is the second half of a double-byte character,
  450.             // insert the two bytes at the same time (flush the double-byte cache)
  451.             db[0] = pWE->firstByte;
  452.             db[1] = theByte;
  453.             charLength = 2;
  454.             pWE->firstByte = 0;
  455.         }
  456.         else
  457.         {
  458.  
  459.             // if theByte is the first half of a double-byte character, just cache it and exit
  460.             if (CallWECharByteProc(&theByte, 0, FontToScript(pWE->nullStyle.runStyle.tsFont),
  461.                 hWE, pWE->charByteHook) == smFirstByte)
  462.             {
  463.                 pWE->firstByte = theByte;
  464.                 return noErr;
  465.             }
  466.         }
  467.  
  468.     } // if double-byte script installed
  469.  
  470.     // insert the new character into the text
  471.     if ((err = _WEInsertText(offset, db, charLength, hWE)) != noErr)
  472.         goto cleanup2;
  473.  
  474.     // adjust undo buffer for the new character
  475.     _WEAdjustUndoRange(charLength, hWE);
  476.  
  477.     // invalid the null style
  478.     BCLR(pWE->flags, weFUseNullStyle);
  479.  
  480.     // move the insertion point after the new character
  481.     endOffset = offset + charLength;
  482.     pWE->selStart = endOffset;
  483.     pWE->selEnd = endOffset;
  484.  
  485.     // redraw the text
  486.     if ((err = _WERedraw(offset, endOffset, hWE)) != noErr)
  487.         goto cleanup2;
  488.  
  489. cleanup1:
  490.     // clear result code
  491.     err = noErr;
  492.  
  493. cleanup2:
  494.     // return result code
  495.     return err;
  496.  
  497. }
  498.  
  499. pascal OSErr _WEBackspace(WEHandle hWE)
  500. {
  501.     // this routine is called by WEKey to handle the backspace key
  502.  
  503.     WEPtr pWE = *hWE;    // assume WE record is already locked
  504.     WEActionPtr pAction;
  505.     SInt32 rangeStart, rangeEnd, charLength;
  506.     WERunInfo runInfo;
  507.     char db[2];
  508.     Boolean saveActionLock;
  509.     OSErr err;
  510.  
  511.     // calculate the text range to delete
  512.     // if the selection is non-empty, delete that
  513.     rangeStart = pWE->selStart;
  514.     rangeEnd = pWE->selEnd;
  515.     if (rangeStart == rangeEnd)
  516.     {
  517.  
  518.         // otherwise the selection is an insertion point
  519.         // do nothing if insertion point is at the beginning of the text
  520.         if (rangeStart == 0)
  521.             return noErr;
  522.  
  523.         // determine the byte-type of the character preceding the insertion point
  524.         charLength = (WECharByte(rangeStart - 1, hWE) == smSingleByte) ? 1 : 2;
  525.         rangeStart -= charLength;
  526.  
  527.         if (pWE->hActionStack != nil)
  528.         {
  529.             // UNDO SUPPORT FOR BACKSPACES
  530.  
  531.             // lock the action record
  532.             saveActionLock = _WESetHandleLock((Handle) pWE->hActionStack, true);
  533.             pAction = *pWE->hActionStack;
  534.  
  535.             // backspaces over the newly entered text aren't a problem
  536.             if (pAction->delRangeLength > 0)
  537.                 pAction->delRangeLength -= charLength;
  538.             else
  539.             {
  540.  
  541.                 // the hard part comes when backspacing past the new text because
  542.                 // the user is about to delete a character not included in the block we saved
  543.                 db[0] = WEGetChar(rangeStart, hWE);
  544.                 if (charLength == 2)
  545.                 {
  546.                     db[1] = WEGetChar(rangeStart + 1, hWE);
  547.                 }
  548.  
  549.                 // prepend the character to be deleted to the beginning of our saved text handle
  550.                 if ((err = _WESplice(pAction->hText, &db, charLength, 0)) != noErr)
  551.                     return err;
  552.  
  553.                 // adjust internal counters
  554.                 pAction->insRangeLength += charLength;
  555.                 pAction->delRangeStart -= charLength;
  556.  
  557.                 // get style run info associated with the about-to-be-deleted character
  558.                 WEGetRunInfo(rangeStart, &runInfo, hWE);
  559.  
  560.                 // prepend a new style element to our style scrap, if necessary
  561.                 if ((err = _WEPrependStyle(pAction->hStyles, &runInfo, charLength)) != noErr)
  562.                     return err;
  563.  
  564. #if WASTE_OBJECTS
  565.                 // do the same with our object "soup"
  566.                 if ((err = _WEPrependObject(pAction->hSoup, &runInfo, charLength)) != noErr)
  567.                     return err;
  568. #endif
  569.  
  570.             } // if deleting old text
  571.  
  572.             // unlock the action record
  573.             _WESetHandleLock((Handle) pWE->hActionStack, saveActionLock);
  574.  
  575.         } // if undo support is enabled
  576.     } // if selection is empty
  577.  
  578.     if ((err = _WEDeleteRange(rangeStart, rangeEnd, hWE)) != noErr)
  579.         return err;
  580.  
  581.     // keep track of current selection range
  582.     pWE->selStart = rangeStart;
  583.     pWE->selEnd = rangeStart;
  584.  
  585.     // redraw the text
  586.     err = _WERedraw(rangeStart, rangeStart, hWE);
  587.  
  588.     return err;
  589. }
  590.  
  591. pascal OSErr _WEForwardDelete(WEHandle hWE)
  592. {
  593.  
  594.     // this routine is called by WEKey to handle the forward delete key
  595.  
  596.     WEPtr pWE = *hWE;    // assume WE record is already locked
  597.     WEActionPtr pAction;
  598.     SInt32 rangeStart, rangeEnd, charLength;
  599.     WERunInfo runInfo;
  600.     char db[2];
  601.     Boolean saveActionLock;
  602.     OSErr err;
  603.  
  604.     // calculate the text range to delete
  605.     // if the selection is non-empty, delete that
  606.     rangeStart = pWE->selStart;
  607.     rangeEnd = pWE->selEnd;
  608.     if (rangeStart == rangeEnd)
  609.     {
  610.  
  611.         // otherwise the selection is an insertion point
  612.         // do nothing if insertion point is at the end of the text
  613.         if (rangeStart == pWE->textLength)
  614.             return noErr;
  615.  
  616.         // determine the byte-type of the character following the insertion point
  617.         charLength = (WECharByte(rangeStart, hWE) == smSingleByte) ? 1 : 2;
  618.         rangeEnd = rangeStart + charLength;
  619.  
  620.         if (pWE->hActionStack != nil)
  621.         {
  622.  
  623.             // UNDO SUPPORT FOR FORWARD DELETE
  624.  
  625.             // lock the action record
  626.             saveActionLock = _WESetHandleLock((Handle) pWE->hActionStack, true);
  627.             pAction = *pWE->hActionStack;
  628.  
  629.             // make a copy of the character about to be deleted
  630.             db[0] = WEGetChar(rangeStart, hWE);
  631.             if (charLength == 2)
  632.             {
  633.                 db[1] = WEGetChar(rangeStart + 1, hWE);
  634.             }
  635.  
  636.             // append it to the end of our saved text handle
  637.             if ((err = _WESplice(pAction->hText, &db, charLength, -1)) != noErr)
  638.                 return err;
  639.  
  640.             // get style run info associated with the about-to-be-deleted character
  641.             WEGetRunInfo(rangeStart, &runInfo, hWE);
  642.  
  643.             // append a new style element to our style scrap, if necessary
  644.             if ((err = _WEAppendStyle(pAction->hStyles, &runInfo, pAction->insRangeLength)) != noErr)
  645.                 return err;
  646.  
  647. #if WASTE_OBJECTS
  648.             // do the same with our object soup
  649.             if ((err = _WEAppendObject(pAction->hSoup, &runInfo, pAction->insRangeLength)) != noErr)
  650.                 return err;
  651. #endif
  652.  
  653.             // adjust internal counters
  654.             pAction->insRangeLength += charLength;
  655.  
  656.             // unlock the action record
  657.             _WESetHandleLock((Handle) pWE->hActionStack, saveActionLock);
  658.  
  659.         } // if undo support is enabled
  660.     } // if selection is empty
  661.  
  662.     if ((err = _WEDeleteRange(rangeStart, rangeEnd, hWE)) != noErr)
  663.         return err;
  664.  
  665.     // keep track of current selection range
  666.     pWE->selStart = rangeStart;
  667.     pWE->selEnd = rangeStart;
  668.  
  669.     // redraw the text
  670.     err = _WERedraw(rangeStart, rangeStart, hWE);
  671.  
  672.     return err;
  673. }
  674.  
  675. pascal Boolean WEIsTyping(WEHandle hWE)
  676. {
  677.     // return true if we're tracking a typing sequence in the specified WE instance
  678.  
  679.     WEPtr pWE = *hWE;
  680.     WEActionPtr pAction;
  681.  
  682.     // there must be an undo buffer
  683.     if (pWE->hActionStack == nil)
  684.         return false;
  685.  
  686.     pAction = *pWE->hActionStack;
  687.  
  688.     // the action kind must be "typing" and the redo flag must be clear
  689.     if ((pAction->actionKind != weAKTyping) || ((pAction->actionFlags & weAFIsRedo) != 0))
  690.         return false;
  691.  
  692.     // finally, the selection range mustn't have moved since the last WEKey
  693.     if ((pWE->selStart != pWE->selEnd) ||
  694.         (pWE->selStart != pAction->delRangeStart + pAction->delRangeLength))
  695.         return false;
  696.  
  697.     return true;
  698. }
  699.  
  700. pascal void WEKey(SInt16 key, EventModifiers modifiers, WEHandle hWE)
  701. {
  702.     WEPtr pWE;
  703.     WEActionHandle hAction;
  704.     Boolean saveWELock;
  705.  
  706.     // lock the WE record
  707.     saveWELock = _WESetHandleLock((Handle) hWE, true);
  708.     pWE = *hWE;
  709.  
  710.     // hide the caret if it's showing
  711.     if (BTST(pWE->flags, weFCaretVisible))
  712.         _WEBlinkCaret(hWE);
  713.  
  714.     // hide the cursor (it will show again as soon as it's moved)
  715.     ObscureCursor();
  716.  
  717.     // dispatch on key class (arrow keys, printable characters, backspace)
  718.     if ((key >= kArrowLeft) && (key <= kArrowDown))
  719.     {
  720.         _WEDoArrowKey(key, modifiers, hWE);
  721.     }
  722.     else
  723.     {
  724.  
  725.         // non-arrow keys modify the text, so make sure editing is allowed
  726.         if (!BTST(pWE->features, weFReadOnly))
  727.         {
  728.             // are we tracking a typing sequence?
  729.             if (!WEIsTyping(hWE))
  730.             {
  731.                 // nope;  start a new one
  732.                 // increment modification count
  733.                 pWE->modCount++;
  734.  
  735.                 // if undo support is enabled, create a new action to keep track of typing
  736.                 if (BTST(pWE->features, weFUndoSupport))
  737.                 {
  738.                     WEClearUndo(hWE);
  739.                     if (_WENewAction(pWE->selStart, pWE->selEnd, 0, weAKTyping, 0, hWE, &hAction) == noErr)
  740.                     {
  741.                         _WEPushAction(hAction);
  742.                     }
  743.                 }
  744.             } // if WEIsTyping
  745.  
  746.             if (key == kBackspace)
  747.             {
  748.                 _WEBackspace(hWE);
  749.             }
  750.             else if (key == kForwardDelete)
  751.             {
  752.                 _WEForwardDelete(hWE);
  753.             }
  754.             else
  755.             {
  756.                 _WETypeChar(key, hWE);
  757.             }
  758.         } // if not read-only
  759.     }
  760.  
  761.     // unlock the WE record
  762.     _WESetHandleLock((Handle) hWE, saveWELock);
  763. }
  764.  
  765. pascal OSErr WEInsert(Ptr textPtr, SInt32 textLength, StScrpHandle hStyles, Handle hSoup, WEHandle hWE)
  766. {
  767. #if !WASTE_OBJECTS
  768. #pragma unused(hSoup)
  769. #endif
  770.     WEPtr pWE;
  771.     SInt32 offset, endOffset;
  772.     WEActionHandle hAction;
  773.     SInt16 intPasteAction;
  774.     Boolean saveWELock;
  775.     char space = kSpace;
  776.     OSErr err;
  777.  
  778.     // lock the WE record
  779.     saveWELock = _WESetHandleLock((Handle) hWE, true);
  780.     pWE = *hWE;
  781.     offset = pWE->selStart;
  782.  
  783.     // return an error code if this instance is read-only
  784.     err = weReadOnlyErr;
  785.     if (BTST(pWE->features, weFReadOnly))
  786.         goto cleanup;
  787.  
  788.     // stop any ongoing inline input session
  789.     WEStopInlineSession(hWE);
  790.  
  791.     // increment modification count
  792.     pWE->modCount++;
  793.  
  794.     // if undo support is enabled, save current selection range
  795.     if (BTST(pWE->features, weFUndoSupport))
  796.     {
  797.         WEClearUndo(hWE);
  798.         if (_WENewAction(offset, pWE->selEnd, textLength, weAKUnspecified, 0, hWE, &hAction) == noErr)
  799.         {
  800.             _WEPushAction(hAction);
  801.         }
  802.     }
  803.  
  804.     // delete current selection
  805.     if ((err = _WEDeleteRange(offset, pWE->selEnd, hWE)) != noErr)
  806.         goto cleanup;
  807.  
  808.     // insert the new text at the insertion point
  809.     if ((err = _WEInsertText(offset, textPtr, textLength, hWE)) != noErr)
  810.         goto cleanup;
  811.     endOffset = offset + textLength;
  812.  
  813.     if (hStyles != nil)
  814.     {
  815.  
  816.         // if a style scrap was supplied, apply it to the newly inserted text
  817.         if ((err = _WEApplyStyleScrap(offset, endOffset, hStyles, hWE)) != noErr)
  818.             goto cleanup;
  819.     }
  820.  
  821. #if WASTE_OBJECTS
  822.     if (hSoup != nil)
  823.     {
  824.         // if an object soup was supplied, apply it to the newly inserted text
  825.         if ((err = _WEApplySoup(offset, hSoup, hWE)) != noErr)
  826.             goto cleanup;
  827.     }
  828. #endif
  829.  
  830.     // determine whether an extra space should be added before or after the inserted text
  831.     intPasteAction = _WEIntelligentPaste(offset, endOffset, hWE);
  832.  
  833.     // add the extra space, if necessary
  834.     if (intPasteAction != weDontAddSpaces)
  835.     {
  836.         if (intPasteAction == weAddSpaceOnLeftSide)
  837.         {
  838.             err = _WEInsertText(offset, &space, sizeof(space), hWE);
  839.         }
  840.         else
  841.         {
  842.             err = _WEInsertText(endOffset, &space, sizeof(space), hWE);
  843.         }
  844.         if (err != noErr)
  845.             goto cleanup;
  846.         endOffset++;
  847.  
  848.         // adjust undo buffer (if any) for the extra space
  849.         _WEAdjustUndoRange(sizeof(space), hWE);
  850.     }
  851.  
  852.     // invalid the null style
  853.     BCLR(pWE->flags, weFUseNullStyle);
  854.  
  855.     // move the insertion point at the end of the inserted text
  856.     pWE->selStart = endOffset;
  857.     pWE->selEnd = endOffset;
  858.  
  859.     // redraw the text
  860.     if ((err = _WERedraw(offset, endOffset, hWE)) != noErr)
  861.         goto cleanup;
  862.  
  863.     // clear result code
  864.     err = noErr;
  865.  
  866. cleanup:
  867.     // unlock the WE record
  868.     _WESetHandleLock((Handle) hWE, saveWELock);
  869.  
  870.     // return result code
  871.     return err;
  872. }
  873.  
  874. #if WASTE_OBJECTS
  875.  
  876. pascal OSErr WEInsertObject(FlavorType objectType, Handle objectDataHandle, Point objectSize, WEHandle hWE)
  877. {
  878.     WEPtr pWE;
  879.     WEActionHandle hAction;
  880.     SInt32 offset, endOffset;
  881.     WETextStyle ts;
  882.     Boolean saveWELock;
  883.     char marker = kObjectMarker;
  884.     OSErr err;
  885.  
  886.     BLOCK_CLR(ts);
  887.  
  888.     // lock the WE record
  889.     saveWELock = _WESetHandleLock((Handle) hWE, true);
  890.     pWE = *hWE;
  891.     offset = pWE->selStart;
  892.  
  893.     // return an error code if this instance is read-only
  894.     err = weReadOnlyErr;
  895.     if (BTST(pWE->features, weFReadOnly))
  896.         goto cleanup;
  897.  
  898.     // stop any ongoing inline input session
  899.     WEStopInlineSession(hWE);
  900.  
  901.     // call the 'new' handler to initialize private object storage (if any)
  902.     // and to calculate the default size for this object
  903.  
  904.     if ((err = _WENewObject(objectType, objectDataHandle, hWE, &ts.tsObject)) != noErr)
  905.         goto cleanup;
  906.  
  907.     // use the specified object size, unless it is (0, 0), in which case keep the default size
  908.     if (* (SInt32 *) &objectSize != 0)
  909.     {
  910.         (*ts.tsObject)->objectSize = objectSize;
  911.     }
  912.  
  913.     // increment modification count
  914.     pWE->modCount++;
  915.  
  916.     // if undo support is enabled, save current selection range
  917.     if (BTST(pWE->features, weFUndoSupport))
  918.     {
  919.         WEClearUndo(hWE);
  920.         if (_WENewAction(offset, pWE->selEnd, 1, weAKUnspecified, 0, hWE, &hAction) == noErr)
  921.         {
  922.             _WEPushAction(hAction);
  923.         }
  924.     }
  925.  
  926.     // delete current selection
  927.     if ((err = _WEDeleteRange(offset, pWE->selEnd, hWE)) != noErr)
  928.         goto cleanup;
  929.  
  930.     // insert a kObjectMarker character at the insertion point
  931.     if ((err = _WEInsertText(offset, &marker, sizeof(marker), hWE)) != noErr)
  932.         goto cleanup;
  933.  
  934.     // move the insertion point after the inserted text
  935.     endOffset = offset + 1;
  936.     pWE->selStart = endOffset;
  937.     pWE->selEnd = endOffset;
  938.  
  939.     // record a reference to the object descriptor in the style table
  940.     err = _WESetStyleRange(offset, endOffset, weDoObject, &ts, hWE);
  941.     ts.tsObject = nil;
  942.     if (err != noErr)
  943.         goto cleanup;
  944.  
  945.     // invalid the null style
  946.     BCLR(pWE->flags, weFUseNullStyle);
  947.  
  948.     // redraw the text
  949.     if ((err = _WERedraw(offset, endOffset, hWE)) != noErr)
  950.         goto cleanup;
  951.  
  952.     // clear result code
  953.     err = noErr;
  954.  
  955. cleanup:
  956.     // clean up
  957.     _WEForgetHandle((Handle *) &ts.tsObject);
  958.  
  959.     // unlock the WE record
  960.     _WESetHandleLock((Handle) hWE, saveWELock);
  961.  
  962.     // return result code
  963.     return err;
  964. }
  965.  
  966. #endif
  967.  
  968. pascal OSErr WEDelete(WEHandle hWE)
  969. {
  970.     WEPtr pWE;
  971.     WEActionHandle hAction;
  972.     SInt32 rangeStart, rangeEnd;
  973.     Boolean saveWELock;
  974.     OSErr err;
  975.  
  976.     // lock the WE record
  977.     saveWELock = _WESetHandleLock((Handle) hWE, true);
  978.     pWE = *hWE;
  979.  
  980.     // return an error code if this instance is read-only
  981.     err = weReadOnlyErr;
  982.     if (BTST(pWE->features, weFReadOnly))
  983.         goto cleanup;
  984.  
  985.     // stop any ongoing inline input session
  986.     WEStopInlineSession(hWE);
  987.  
  988.     // get current selection range
  989.     rangeStart = pWE->selStart;
  990.     rangeEnd = pWE->selEnd;
  991.  
  992.     // do nothing if the selection range is empty
  993.     if (rangeStart < rangeEnd)
  994.     {
  995.  
  996.         // increment modification count
  997.         pWE->modCount++;
  998.  
  999.         // range extension for intelligent cut-and-paste
  1000.         _WEIntelligentCut(&rangeStart, &rangeEnd, hWE);
  1001.  
  1002.         // if undo support is enabled, save the range to be deleted
  1003.         if (BTST(pWE->features, weFUndoSupport))
  1004.         {
  1005.             WEClearUndo(hWE);
  1006.             if (_WENewAction(rangeStart, rangeEnd, 0, weAKClear, 0, hWE, &hAction) == noErr)
  1007.             {
  1008.                 _WEPushAction(hAction);
  1009.             }
  1010.         }
  1011.  
  1012.         // delete the selection range
  1013.         if ((err = _WEDeleteRange(rangeStart, rangeEnd, hWE)) != noErr)
  1014.             goto cleanup;
  1015.  
  1016.         // reset the selection range
  1017.         pWE->selStart = rangeStart;
  1018.         pWE->selEnd = rangeStart;
  1019.  
  1020.         // redraw the text
  1021.         if ((err = _WERedraw(rangeStart, rangeStart, hWE)) != noErr)
  1022.             goto cleanup;
  1023.  
  1024.     } // if non-empty selection
  1025.  
  1026.     // clear result code
  1027.     err = noErr;
  1028.  
  1029. cleanup:
  1030.     // unlock the WE record
  1031.     _WESetHandleLock((Handle) hWE, saveWELock);
  1032.  
  1033.     // return result code
  1034.     return err;
  1035. }
  1036.  
  1037. pascal OSErr WECut(WEHandle hWE)
  1038. {
  1039.     OSErr err;
  1040.  
  1041.     // first copy...
  1042.     if ((err = WECopy(hWE)) != noErr)
  1043.         goto cleanup;
  1044.  
  1045.     // ... then delete
  1046.     if ((err = WEDelete(hWE)) != noErr)
  1047.         goto cleanup;
  1048.  
  1049.     // change the action kind of the most recent action, if any
  1050.     if ((*hWE)->hActionStack != nil)
  1051.     {
  1052.         (*(*hWE)->hActionStack)->actionKind = weAKCut;
  1053.     }
  1054.  
  1055. cleanup:
  1056.     // return result code
  1057.     return err;
  1058. }
  1059.  
  1060. pascal Boolean WECanPaste(WEHandle hWE)
  1061. {
  1062.     SInt32 scrapOffset;
  1063. #if WASTE_OBJECTS
  1064.     FlavorType objectType;
  1065.     SInt32 index;
  1066. #endif
  1067.  
  1068.     if (!BTST((*hWE)->features, weFReadOnly))
  1069.     {
  1070.         // return true if the desk scrap contains a text flavor
  1071.         if (GetScrap(nil, kTypeText, &scrapOffset) > 0)
  1072.             return true;
  1073.  
  1074. #if WASTE_OBJECTS
  1075.         // see if the desk scrap contains a flavor matching one of the registered object types
  1076.         index = 0;
  1077.         while (_WEGetIndObjectType(index, &objectType, hWE) == noErr)
  1078.         {
  1079.             if (GetScrap(nil, objectType, &scrapOffset) > 0)
  1080.                 return true;
  1081.             index++;
  1082.         } // while
  1083. #endif
  1084.     } // if not read-only
  1085.     return false;
  1086. }
  1087.  
  1088. pascal OSErr WEPaste(WEHandle hWE)
  1089. {
  1090.     Handle hItem = nil;
  1091.     Handle hStyles = nil;
  1092.     Handle hSoup = nil;
  1093.     SInt32 scrapOffset;
  1094. #if WASTE_OBJECTS
  1095.     FlavorType objectType;
  1096.     SInt32 index;
  1097. #endif
  1098.     OSErr err;
  1099.  
  1100.     // allocate a handle to hold a scrap item
  1101.     if ((err = _WEAllocate(0, kAllocTemp, &hItem)) != noErr)
  1102.         goto cleanup;
  1103.  
  1104.     // look for a text flavor
  1105.     if (GetScrap(hItem, kTypeText, &scrapOffset) <= 0)
  1106.     {
  1107.  
  1108. #if WASTE_OBJECTS
  1109.         // no text: look for a flavor matching one of the registered object types
  1110.         index = 0;
  1111.         while (_WEGetIndObjectType(index, &objectType, hWE) == noErr)
  1112.         {
  1113.             if (GetScrap(hItem, objectType, &scrapOffset) > 0)
  1114.             {
  1115.                 Point objectSize;
  1116.                 * (SInt32 *) &objectSize = 0;
  1117.  
  1118.                 // found a registered type: create a new object out of the tagged data
  1119.                 err = WEInsertObject(objectType, hItem, objectSize, hWE);
  1120.  
  1121.                 // if successful, set hItem to nil so clean-up section won't kill the object data
  1122.                 if (err == noErr)
  1123.                     hItem = nil;
  1124.                 goto cleanup;
  1125.             }
  1126.  
  1127.             // try with next flavor
  1128.             index++;
  1129.         } // while
  1130. #endif
  1131.  
  1132.         // nothing pasteable: return an error code
  1133.         err = noTypeErr;
  1134.         goto cleanup;
  1135.     }
  1136.  
  1137.     if (!BTST((*hWE)->features, weFMonoStyled))
  1138.     {
  1139.         // allocate a handle to hold the style scrap, if any
  1140.         if ((err = _WEAllocate(0, kAllocTemp, &hStyles)) != noErr)
  1141.             goto cleanup;
  1142.  
  1143.         // look for a 'styl' item accompanying the text
  1144.         if (GetScrap(hStyles, kTypeStyles, &scrapOffset) <= 0)
  1145.             // forget the handle if nothing was found or an error occurred
  1146.             _WEForgetHandle(&hStyles);
  1147.  
  1148. #if WASTE_OBJECTS
  1149.         // allocate a handle to hold the soup, if any
  1150.         if ((err = _WEAllocate(0, kAllocTemp, &hSoup)) != noErr)
  1151.             goto cleanup;
  1152.  
  1153.         // look for a 'SOUP' item accompanying the text
  1154.         if (GetScrap(hSoup, kTypeSoup, &scrapOffset) <= 0)
  1155.             // forget the handle if nothing was found or an error occurred
  1156.             _WEForgetHandle(&hSoup);
  1157. #endif
  1158.     } // if not mono-styled
  1159.  
  1160.     // lock down the text
  1161.     HLock(hItem);
  1162.  
  1163.     // insert the text
  1164.     err = WEInsert(*hItem, GetHandleSize(hItem), (StScrpHandle) hStyles, hSoup, hWE);
  1165.  
  1166. cleanup:
  1167.     // if successful, change the action kind of the most recent action, if any
  1168.     if ((err == noErr) && ((*hWE)->hActionStack != nil))
  1169.     {
  1170.         (*(*hWE)->hActionStack)->actionKind = weAKPaste;
  1171.     }
  1172.  
  1173.     // clean up
  1174.     _WEForgetHandle(&hItem);
  1175.     _WEForgetHandle(&hStyles);
  1176. #if WASTE_OBJECTS
  1177.     _WEForgetHandle(&hSoup);
  1178. #endif
  1179.  
  1180.     // return result code
  1181.     return err;
  1182. }
  1183.  
  1184. pascal OSErr _WESmartSetFont(WEStyleMode mode, const TextStyle *ts, WEHandle hWE)
  1185. {
  1186.     WEPtr pWE = *hWE;    // assume WE record is already locked
  1187.     ScriptCode script;
  1188.     SInt32 runIndex;
  1189.     SInt32 rangeStart, rangeEnd;
  1190.     WERunInfo runInfo;
  1191.     GrafPtr savePort;
  1192.     SInt16 saveFont;
  1193.     OSErr err;
  1194.  
  1195.     // set up the graphics port
  1196.     GetPort(&savePort);
  1197.     SetPort(pWE->port);
  1198.     saveFont = pWE->port->txFont;
  1199.  
  1200.     // get the script corresponding to the font we're applying
  1201.     script = FontToScript(ts->tsFont);
  1202.  
  1203.     // walk through the style runs encompassing the selection range
  1204.     runIndex = WEOffsetToRun(pWE->selStart, hWE);
  1205.     do {
  1206.         _WEGetIndStyle(runIndex, &runInfo, hWE);
  1207.  
  1208.         if (pWE->selStart > runInfo.runStart)
  1209.             rangeStart = pWE->selStart;
  1210.         else
  1211.             rangeStart = runInfo.runStart;
  1212.  
  1213.         if (pWE->selEnd < runInfo.runEnd)
  1214.             rangeEnd = pWE->selEnd;
  1215.         else
  1216.             rangeEnd = runInfo.runEnd;
  1217.  
  1218.         // does this style run belong to the same script we're applying?
  1219.         if (FontToScript(runInfo.runAttrs.runStyle.tsFont) == script)
  1220.         {
  1221.             if ((err = _WESetStyleRange(rangeStart, rangeEnd, weDoFont, (WETextStyle *) ts, hWE)) != noErr)
  1222.                 goto cleanup;
  1223.             runIndex = WEOffsetToRun(runInfo.runEnd, hWE);
  1224.         }
  1225.         else if ((mode & weDoExtractSubscript) != 0)
  1226.         {
  1227.             SInt32 runLength;
  1228.             SInt32 subrunLength;
  1229.             ScriptRunStatus runStatus;
  1230.  
  1231.             // FindScriptRun takes an implicit parameter through the txFont field of thePort
  1232.             TextFont(runInfo.runAttrs.runStyle.tsFont);
  1233.  
  1234.             runLength = rangeEnd - rangeStart;
  1235.             while (runLength > 0)
  1236.             {
  1237.                 // lock text handle
  1238.                 Boolean saveTextLock = _WESetHandleLock(pWE->hText, true);
  1239.  
  1240.                 // look for blocks of subscript text
  1241.                 runStatus = FindScriptRun(*pWE->hText + rangeStart, runLength, &subrunLength);
  1242.  
  1243.                 // unlock text handle
  1244.                 _WESetHandleLock(pWE->hText, saveTextLock);
  1245.  
  1246.                 if (runStatus.script == script)
  1247.                 {
  1248.                     // "extract" subscript text
  1249.                     if ((err = _WESetStyleRange(rangeStart, rangeStart + subrunLength, weDoFont, (WETextStyle *) ts, hWE)) != noErr)
  1250.                         goto cleanup;
  1251.                 }
  1252.                 rangeStart += subrunLength;
  1253.                 runLength -= subrunLength;
  1254.             }
  1255.             runIndex = WEOffsetToRun(runInfo.runEnd, hWE);
  1256.         }
  1257.         else
  1258.             runIndex++;
  1259.  
  1260.     } while (runInfo.runEnd < pWE->selEnd);
  1261.  
  1262. cleanup:
  1263.     // restore the port
  1264.     TextFont(saveFont);
  1265.     SetPort(savePort);
  1266.  
  1267.     // return result code
  1268.     return err;
  1269. }
  1270.  
  1271. pascal OSErr WESetStyle(WEStyleMode mode, const TextStyle *ts, WEHandle hWE)
  1272. {
  1273.     WEPtr pWE;
  1274.     WEActionHandle hAction;
  1275.     ScriptCode fontScript;
  1276.     Boolean saveWELock;
  1277.     OSErr err;
  1278.  
  1279.     // lock the WE record
  1280.     saveWELock = _WESetHandleLock((Handle) hWE, true);
  1281.     pWE = *hWE;
  1282.  
  1283.     // return an error code if this instance is read-only
  1284.     err = weReadOnlyErr;
  1285.     if (BTST(pWE->features, weFReadOnly))
  1286.     {
  1287.         goto cleanup;
  1288.     }
  1289.  
  1290.     // stop any ongoing inline input session
  1291.     WEStopInlineSession(hWE);
  1292.  
  1293.     if (BTST(pWE->features, weFMonoStyled))
  1294.     {
  1295.         // MONOSTYLED TEXT
  1296.         // apply the change to the whole text, not just to the selection range
  1297.         if ((err = _WESetStyleRange(0, pWE->textLength, mode, (WETextStyle *) ts, hWE)) != noErr)
  1298.         {
  1299.             goto cleanup;
  1300.         }
  1301.  
  1302.         // redraw the text
  1303.         if ((err = _WERedraw(0, pWE->textLength, hWE)) != noErr)
  1304.         {
  1305.             goto cleanup;
  1306.         }
  1307.     }
  1308.     else if (pWE->selStart == pWE->selEnd)
  1309.     {
  1310.         // MULTISTYLED TEXT; NULL SELECTION
  1311.         // first make sure the nullStyle field contains valid information
  1312.         _WESynchNullStyle(hWE);
  1313.  
  1314.         // apply style changes to the nullStyle record
  1315.         _WECopyStyle((WETextStyle *) ts, &pWE->nullStyle.runStyle, pWE->nullStyle.runStyle.tsFace, mode);
  1316.  
  1317.         // special case: if this instance is empty, propagate the
  1318.         // change to the style table (this avoids some subtle problems)
  1319.         if (pWE->textLength == 0)
  1320.         {
  1321.             if ((err = _WESetStyleRange(0, 0, weDoAll + weDoReplaceFace, &pWE->nullStyle.runStyle, hWE)) != noErr)
  1322.                 goto cleanup;
  1323.         }
  1324.  
  1325. #if !WASTE_NO_SYNCH
  1326.         // if the font was altered, synchronize the keyboard script
  1327.         if (BTST(pWE->flags, weFNonRoman) && (mode & weDoFont))
  1328.         {
  1329.             fontScript = FontToScript(pWE->nullStyle.runStyle.tsFont);
  1330.             if (fontScript != GetScriptManagerVariable(smKeyScript))
  1331.             {
  1332.                 KeyScript(fontScript);
  1333.             }
  1334.         }
  1335. #endif
  1336.     }
  1337.     else
  1338.     {
  1339.         // MULTISTYLED TEXT; NON-EMPTY SELECTION
  1340.  
  1341.         // increment modification count
  1342.         pWE->modCount++;
  1343.  
  1344.         // if undo support is enabled, save the styles of the text range to be affected
  1345.         if (BTST(pWE->features, weFUndoSupport))
  1346.         {
  1347.             WEClearUndo(hWE);
  1348.             if (_WENewAction(pWE->selStart, pWE->selEnd, pWE->selEnd - pWE->selStart, weAKSetStyle,
  1349.                 weAFDontSaveText + weAFDontSaveSoup, hWE, &hAction) == noErr)
  1350.             {
  1351.                 _WEPushAction(hAction);
  1352.             }
  1353.         }
  1354.  
  1355.         // check for "smart" font modes
  1356.         if (BTST(pWE->flags, weFNonRoman) && ((mode & weDoSmartFont) == weDoSmartFont))
  1357.         {
  1358.             if ((err = _WESmartSetFont(mode, ts, hWE)) != noErr)
  1359.                 goto cleanup;
  1360.             mode &= ~weDoFont;
  1361.         }
  1362.  
  1363.         // set the style of the selection range
  1364.         if ((err = _WESetStyleRange(pWE->selStart, pWE->selEnd, mode, (WETextStyle *) ts, hWE)) != noErr)
  1365.             goto cleanup;
  1366.  
  1367.         // and redraw the text
  1368.         if ((err = _WERedraw(pWE->selStart, pWE->selEnd, hWE)) != noErr)
  1369.             goto cleanup;
  1370.     }
  1371.  
  1372.     // clear the result code
  1373.     err = noErr;
  1374.  
  1375. cleanup:
  1376.     // unlock the WE record
  1377.     _WESetHandleLock((Handle) hWE, saveWELock);
  1378.  
  1379.     // return result code
  1380.     return err;
  1381. }
  1382.  
  1383. pascal OSErr WEUseStyleScrap(StScrpHandle hStyles, WEHandle hWE)
  1384. {
  1385.     WEPtr pWE;
  1386.     Boolean saveWELock;
  1387.     OSErr err;
  1388.  
  1389.     // lock the WE record
  1390.     saveWELock = _WESetHandleLock((Handle) hWE, true);
  1391.     pWE = *hWE;
  1392.  
  1393.     // return an error code if this instance is read-only
  1394.     err = weReadOnlyErr;
  1395.     if (BTST(pWE->features, weFReadOnly))
  1396.         goto cleanup;
  1397.  
  1398.     // apply the style scrap to the selection range
  1399.     if ((err = _WEApplyStyleScrap(pWE->selStart, pWE->selEnd, hStyles, hWE)) != noErr)
  1400.         goto cleanup;
  1401.  
  1402.     // redraw the text
  1403.     err = _WERedraw(pWE->selStart, pWE->selEnd, hWE);
  1404.  
  1405. cleanup:
  1406.     // unlock the WE record
  1407.     _WESetHandleLock((Handle) hWE, saveWELock);
  1408.  
  1409.     // return result code
  1410.     return err;
  1411. }
  1412.  
  1413. #if WASTE_OBJECTS
  1414.  
  1415. pascal OSErr WEUseSoup(Handle hSoup, WEHandle hWE)
  1416. {
  1417.     WEPtr pWE;
  1418.     Boolean saveWELock;
  1419.     OSErr err;
  1420.  
  1421.     // lock the WE record
  1422.     saveWELock = _WESetHandleLock((Handle) hWE, true);
  1423.     pWE = *hWE;
  1424.  
  1425.     // return an error code if this instance is read-only
  1426.     err = weReadOnlyErr;
  1427.     if (BTST(pWE->features, weFReadOnly))
  1428.         goto cleanup;
  1429.  
  1430.     // apply the soup starting from selStart
  1431.     if ((err = _WEApplySoup(pWE->selStart, hSoup, hWE)) != noErr)
  1432.         goto cleanup;
  1433.  
  1434.     // redraw the text
  1435.     err = _WERedraw(pWE->selStart, pWE->selEnd, hWE);
  1436.  
  1437. cleanup:
  1438.     // unlock the WE record
  1439.     _WESetHandleLock((Handle) hWE, saveWELock);
  1440.  
  1441.     // return result code
  1442.     return err;
  1443. }
  1444.  
  1445. #endif  // WASTE_OBJECTS
  1446.